/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#include "DBManager/Database/CachePool.h"

#include <chrono>
#include <iostream>
#include <set>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

#include <gtest/gtest.h>

#include "DBManager/Database/CacheHelper.h"
#include "DBManager/Database/HDF5Database.h"
#include "DBManager/UnitTest/HDF5/TestDB.h"

using namespace SG::DBManager;

/**
 * @brief CachePool基础功能测试夹具
 */
class CachePoolTest : public ::testing::Test
{
  protected:
    void SetUp () override
    {
        // 创建测试用的缓存池：10个条目，1MB内存限制，1秒清理间隔
        // cachePool = std::make_unique<CachePool> (10, 1024 * 1024, std::chrono::milliseconds (1000));
        HDF5Database* h5db = static_cast<HDF5Database*> (DB::ServiceFactory->GetDatabase ());
        cachePool          = &h5db->GetCachePool ();
    }

    CachePool* cachePool;
};

/**
 * @brief 测试基本的Put和Get操作
 */
TEST_F (CachePoolTest, BasicPutAndGet)
{
    // 测试存储和获取vector
    auto* vec = new std::vector<int> ();
    for (int i = 0; i < 100; ++i)
    {
        vec->push_back (i);
    }

    ASSERT_TRUE (cachePool->Put ("test_vector", vec, std::chrono::milliseconds (5000)));

    auto* retrieved = cachePool->Get<std::vector<int>> ("test_vector");
    ASSERT_NE (retrieved, nullptr);
    ASSERT_EQ (retrieved->size (), 100);
    ASSERT_EQ ((*retrieved)[50], 50);

    // 测试缓存大小
    ASSERT_EQ (cachePool->Size (), 1);
    ASSERT_GT (cachePool->MemoryUsage (), 0);
}

/**
 * @brief 测试不同数据类型的缓存
 */
TEST_F (CachePoolTest, DifferentDataTypes)
{
    cachePool->Clear ();
    // 测试vector
    auto* vec = new std::vector<std::string>{ "hello", "world", "cache" };
    ASSERT_TRUE (cachePool->Put ("vector", vec, std::chrono::milliseconds (10000)));

    // 测试unordered_map
    auto* map      = new std::unordered_map<std::string, int> ();
    (*map)["key1"] = 100;
    (*map)["key2"] = 200;
    ASSERT_TRUE (cachePool->Put ("map", map, std::chrono::milliseconds (10000)));

    // 测试set
    auto* set = new std::set<int>{ 1, 2, 3, 4, 5 };
    ASSERT_TRUE (cachePool->Put ("set", set, std::chrono::milliseconds (10000)));

    // 验证所有数据都能正确获取
    auto* vecRetrieved = cachePool->Get<std::vector<std::string>> ("vector");
    ASSERT_NE (vecRetrieved, nullptr);
    ASSERT_EQ (vecRetrieved->size (), 3);
    ASSERT_EQ ((*vecRetrieved)[0], "hello");

    auto* mapRetrieved = cachePool->Get<std::unordered_map<std::string, int>> ("map");
    ASSERT_NE (mapRetrieved, nullptr);
    ASSERT_EQ (mapRetrieved->size (), 2);
    ASSERT_EQ ((*mapRetrieved)["key1"], 100);

    auto* setRetrieved = cachePool->Get<std::set<int>> ("set");
    ASSERT_NE (setRetrieved, nullptr);
    ASSERT_EQ (setRetrieved->size (), 5);
    ASSERT_EQ (setRetrieved->count (3), 1);

    ASSERT_EQ (cachePool->Size (), 3);
}

/**
 * @brief 测试TTL过期功能
 */
TEST_F (CachePoolTest, TTLExpiration)
{
    auto* data = new std::vector<int>{ 1, 2, 3, 4, 5 };

    // 设置100毫秒TTL
    ASSERT_TRUE (cachePool->Put ("short_ttl", data, std::chrono::milliseconds (100)));

    // 立即获取应该成功
    auto* retrieved = cachePool->Get<std::vector<int>> ("short_ttl");
    ASSERT_NE (retrieved, nullptr);
    ASSERT_TRUE (cachePool->Contains ("short_ttl"));

    // 等待过期
    std::this_thread::sleep_for (std::chrono::milliseconds (150));

    // 过期后获取应该返回nullptr
    auto* expiredData = cachePool->Get<std::vector<int>> ("short_ttl");
    ASSERT_EQ (expiredData, nullptr);
    ASSERT_FALSE (cachePool->Contains ("short_ttl"));
}

/**
 * @brief 测试LRU淘汰策略
 */
// TEST_F (CachePoolTest, LRUEviction)
// {
//     // 创建小容量的缓存池（3个条目）
//     CachePool smallCache (1024 * 1024, std::chrono::milliseconds (30000));

//     // 添加3个条目
//     auto* data1 = new std::vector<int>{ 1 };
//     auto* data2 = new std::vector<int>{ 2 };
//     auto* data3 = new std::vector<int>{ 3 };

//     ASSERT_TRUE (smallCache.Put ("key1", data1));
//     ASSERT_TRUE (smallCache.Put ("key2", data2));
//     ASSERT_TRUE (smallCache.Put ("key3", data3));

//     ASSERT_EQ (smallCache.Size (), 3);

//     // 访问key1，使其成为最近使用的
//     auto* retrieved1 = smallCache.Get<std::vector<int>> ("key1");
//     ASSERT_NE (retrieved1, nullptr);

//     // 添加第4个条目，应该淘汰key2（最久未使用）
//     auto* data4 = new std::vector<int>{ 4 };
//     ASSERT_TRUE (smallCache.Put ("key4", data4));

//     ASSERT_EQ (smallCache.Size (), 4);
//     ASSERT_TRUE (smallCache.Contains ("key1"));   // 最近访问过，应该保留
//     ASSERT_TRUE (smallCache.Contains ("key2"));  // 应该被淘汰
//     ASSERT_TRUE (smallCache.Contains ("key3"));   // 应该保留
//     ASSERT_TRUE (smallCache.Contains ("key4"));   // 新添加的，应该保留
// }

/**
 * @brief 测试Remove和Clear操作
 */
TEST_F (CachePoolTest, RemoveAndClear)
{
    cachePool->Clear ();
    // 添加多个条目
    auto* data1 = new std::vector<int>{ 1, 2, 3 };
    auto* data2 = new std::vector<int>{ 4, 5, 6 };
    auto* data3 = new std::vector<int>{ 7, 8, 9 };

    ASSERT_TRUE (cachePool->Put ("key1", data1));
    ASSERT_TRUE (cachePool->Put ("key2", data2));
    ASSERT_TRUE (cachePool->Put ("key3", data3));

    ASSERT_EQ (cachePool->Size (), 3);

    // 测试单个移除
    ASSERT_TRUE (cachePool->Remove ("key2"));
    ASSERT_EQ (cachePool->Size (), 2);
    ASSERT_FALSE (cachePool->Contains ("key2"));
    ASSERT_TRUE (cachePool->Contains ("key1"));
    ASSERT_TRUE (cachePool->Contains ("key3"));

    // 测试重复移除
    ASSERT_FALSE (cachePool->Remove ("key2"));

    // 测试清空
    cachePool->Clear ();
    ASSERT_EQ (cachePool->Size (), 0);
    ASSERT_FALSE (cachePool->Contains ("key1"));
    ASSERT_FALSE (cachePool->Contains ("key3"));
}

/**
 * @brief 测试手动清理过期项
 */
TEST_F (CachePoolTest, ManualCleanupExpired)
{
    // 添加一些有短TTL的项目
    auto* data1 = new std::vector<int>{ 1 };
    auto* data2 = new std::vector<int>{ 2 };
    auto* data3 = new std::vector<int>{ 3 };

    ASSERT_TRUE (cachePool->Put ("key1", data1, std::chrono::milliseconds (50)));
    ASSERT_TRUE (cachePool->Put ("key2", data2, std::chrono::milliseconds (50)));
    ASSERT_TRUE (cachePool->Put ("key3", data3, std::chrono::milliseconds (10000)));  // 长TTL

    ASSERT_EQ (cachePool->Size (), 3);

    // 等待短TTL过期
    std::this_thread::sleep_for (std::chrono::milliseconds (100));

    // 手动清理
    std::size_t const cleanedCount = cachePool->CleanupExpired ();
    ASSERT_EQ (cleanedCount, 2);                 // 应该清理2个过期项
    ASSERT_EQ (cachePool->Size (), 1);
    ASSERT_TRUE (cachePool->Contains ("key3"));  // 长TTL的应该保留
}

/**
 * @brief 测试线程安全性
 */
TEST_F (CachePoolTest, ThreadSafety)
{
    // 创建小容量缓存池进行线程安全测试，使用很短的清理间隔
    auto testCachePool =
        std::make_unique<SG::DBManager::CachePool> (10 * 1024, std::chrono::milliseconds (100));  // 50个项目，10KB，100ms清理间隔
    testCachePool->StartCleanupThread ();

    const int                numThreads          = 10;
    const int                operationsPerThread = 10;  // 减少操作数避免超过容量
    std::vector<std::thread> threads;

    // 多线程并发操作
    for (int t = 0; t < numThreads; ++t)
    {
        threads.emplace_back ([&testCachePool, t, operationsPerThread] () {
            for (int i = 0; i < operationsPerThread; ++i)
            {
                std::string const key  = "thread" + std::to_string (t) + "_key" + std::to_string (i);
                auto*             data = new std::vector<int>{ t, i };

                // 交替进行Put和Get操作
                if (i % 2 == 0)
                {
                    testCachePool->Put (key, data, std::chrono::milliseconds (1000));  // 缩短TTL到1秒
                }
                else
                {
                    // 尝试获取之前线程可能放入的数据
                    std::string const getKey    = "thread" + std::to_string ((t + 1) % numThreads) + "_key" + std::to_string (i - 1);
                    auto*             retrieved = testCachePool->Get<std::vector<int>> (getKey);
                    if (retrieved)
                    {
                        // 验证数据正确性
                        ASSERT_EQ (retrieved->size (), 2);
                    }
                    delete data;  // 如果没有放入缓存，需要删除
                }
            }
        });
    }

    // 等待所有线程完成
    for (auto& thread : threads)
    {
        thread.join ();
    }

    // 验证缓存池仍然处于一致状态
    ASSERT_LE (testCachePool->Size (), 50);  // 应该不超过最大容量
    std::cout << "Final cache size: " << testCachePool->Size () << '\n';
    std::cout << "Memory usage: " << testCachePool->MemoryUsage () << " bytes" << '\n';
}

/**
 * @brief 测试统计信息
 */
TEST_F (CachePoolTest, Statistics)
{
    // 初始统计
    std::string const initialStats = cachePool->GetStatistics ();
    ASSERT_FALSE (initialStats.empty ());
    std::cout << "Initial statistics:\n" << initialStats << '\n';

    // 添加一些数据
    auto* data1 = new std::vector<int>{ 1, 2, 3 };
    auto* data2 = new std::vector<int>{ 4, 5, 6 };

    ASSERT_TRUE (cachePool->Put ("key1", data1));
    ASSERT_TRUE (cachePool->Put ("key2", data2));

    // 访问数据（命中）
    auto* retrieved1 = cachePool->Get<std::vector<int>> ("key1");
    ASSERT_NE (retrieved1, nullptr);

    // 访问不存在的数据（未命中）
    auto* notFound = cachePool->Get<std::vector<int>> ("nonexistent");
    ASSERT_EQ (notFound, nullptr);

    // 获取更新后的统计
    std::string const updatedStats = cachePool->GetStatistics ();
    std::cout << "Updated statistics:\n" << updatedStats << '\n';

    // 统计信息应该包含命中率等信息
    ASSERT_TRUE (updatedStats.find ("Items") != std::string::npos || updatedStats.find ("Memory") != std::string::npos);
}

/**
 * @brief 测试内存限制
 */
TEST_F (CachePoolTest, MemoryLimit)
{
    // 创建小内存限制的缓存池（1KB）
    CachePool smallMemoryCache (1024, std::chrono::milliseconds (30000));

    // 尝试添加大数据
    auto* largeData = new std::vector<int> ();
    largeData->resize (1000, 42);  // 大约4KB的数据

    ASSERT_TRUE (smallMemoryCache.Put ("large_data", largeData));

    // 添加更多数据，应该触发内存限制
    auto* moreData = new std::vector<int> ();
    moreData->resize (1000, 99);

    // 这个操作可能成功也可能失败，取决于内存管理策略
    smallMemoryCache.Put ("more_data", moreData);

    std::cout << "Small memory cache size: " << smallMemoryCache.Size () << '\n';
    std::cout << "Small memory cache memory usage: " << smallMemoryCache.MemoryUsage () << " bytes" << '\n';
}

/**
 * @brief 测试后台清理线程
 */
TEST_F (CachePoolTest, BackgroundCleanupThread)
{
    // 创建独立的缓存池进行后台清理测试，使用很短的清理间隔
    auto testCachePool = std::make_unique<SG::DBManager::CachePool> (10 * 1024, std::chrono::milliseconds (100));

    // 启动清理线程
    testCachePool->StartCleanupThread ();  // 100ms清理间隔

    // 添加短TTL的数据
    auto* data1 = new std::vector<int>{ 1, 2, 3 };
    auto* data2 = new std::vector<int>{ 4, 5, 6 };

    ASSERT_TRUE (testCachePool->Put ("auto_expire1", data1, std::chrono::milliseconds (200)));
    ASSERT_TRUE (testCachePool->Put ("auto_expire2", data2, std::chrono::milliseconds (200)));

    ASSERT_EQ (testCachePool->Size (), 2);

    // 等待后台清理，等待时间要足够长，清理间隔+TTL时间+缓冲时间
    std::this_thread::sleep_for (std::chrono::milliseconds (500));

    // 数据应该被自动清理
    ASSERT_EQ (testCachePool->Size (), 0);

    // 停止清理线程
    testCachePool->StopCleanupThread ();
}

/**
 * @brief 测试键值覆盖
 */
TEST_F (CachePoolTest, KeyOverwrite)
{
    // 创建独立的缓存池进行覆盖测试
    auto testCachePool = std::make_unique<SG::DBManager::CachePool> (10 * 1024);

    auto* data1 = new std::vector<int>{ 1, 2, 3 };
    auto* data2 = new std::vector<int>{ 4, 5, 6, 7, 8 };

    // 添加第一个数据
    ASSERT_TRUE (testCachePool->Put ("same_key", data1));

    auto* retrieved1 = testCachePool->Get<std::vector<int>> ("same_key");
    ASSERT_NE (retrieved1, nullptr);
    ASSERT_EQ (retrieved1->size (), 3);

    // 使用相同键添加新数据（应该覆盖）
    ASSERT_TRUE (testCachePool->Put ("same_key", data2));

    auto* retrieved2 = testCachePool->Get<std::vector<int>> ("same_key");
    ASSERT_NE (retrieved2, nullptr);
    ASSERT_EQ (retrieved2->size (), 5);  // 新数据

    // 缓存大小应该仍然是1
    ASSERT_EQ (testCachePool->Size (), 1);
}

/**
 * @brief 性能测试 - 大量数据操作
 */
TEST_F (CachePoolTest, PerformanceTest)
{
    // 创建性能测试专用的较大缓存池
    auto testCachePool = std::make_unique<SG::DBManager::CachePool> (1024 * 1024);  // 1200个项目，1MB

    const int dataCount = 1000;
    auto      start     = std::chrono::high_resolution_clock::now ();

    // 批量插入
    for (int i = 0; i < dataCount; ++i)
    {
        auto* data = new std::vector<int> ();
        data->resize (100, i);
        std::string const key = "perf_key_" + std::to_string (i);
        testCachePool->Put (key, data);
    }

    auto insertEnd = std::chrono::high_resolution_clock::now ();

    // 批量查询
    int hitCount = 0;
    for (int i = 0; i < dataCount; ++i)
    {
        std::string const key  = "perf_key_" + std::to_string (i);
        auto*             data = testCachePool->Get<std::vector<int>> (key);
        if (data)
        {
            hitCount++;
        }
    }

    auto queryEnd = std::chrono::high_resolution_clock::now ();

    auto insertTime = std::chrono::duration_cast<std::chrono::milliseconds> (insertEnd - start).count ();
    auto queryTime  = std::chrono::duration_cast<std::chrono::milliseconds> (queryEnd - insertEnd).count ();

    std::cout << "Performance Test Results:" << '\n';
    std::cout << "Inserted " << dataCount << " items in " << insertTime << "ms" << '\n';
    std::cout << "Queried " << dataCount << " items in " << queryTime << "ms" << '\n';
    std::cout << "Hit rate: " << (hitCount * 100.0 / dataCount) << "%" << '\n';
    std::cout << "Final cache size: " << testCachePool->Size () << '\n';

    // 由于缓存大小限制，不是所有数据都能保存
    ASSERT_GT (hitCount, 0);
    ASSERT_LE (testCachePool->Size (), 1200);  // 最大容量限制
}

/**
 * @brief 边界条件测试
 */
TEST_F (CachePoolTest, EdgeCases)
{
    // 测试nullptr数据
    ASSERT_FALSE (cachePool->Put ("null_key", static_cast<std::vector<int>*> (nullptr)));

    // 测试空键
    auto* data = new std::vector<int>{ 1, 2, 3 };
    ASSERT_TRUE (cachePool->Put ("", data));
    auto* retrieved = cachePool->Get<std::vector<int>> ("");
    ASSERT_NE (retrieved, nullptr);

    // 测试零TTL（永不过期）
    auto* permanentData = new std::vector<int>{ 100, 200, 300 };
    ASSERT_TRUE (cachePool->Put ("permanent", permanentData, std::chrono::milliseconds (0)));

    // 等待一段时间，数据应该仍然存在
    std::this_thread::sleep_for (std::chrono::milliseconds (100));
    auto* stillThere = cachePool->Get<std::vector<int>> ("permanent");
    ASSERT_NE (stillThere, nullptr);

    // 测试非常长的键名
    std::string const longKey (1000, 'x');
    auto*             longKeyData = new std::vector<int>{ 999 };
    ASSERT_TRUE (cachePool->Put (longKey, longKeyData));
    auto* longKeyRetrieved = cachePool->Get<std::vector<int>> (longKey);
    ASSERT_NE (longKeyRetrieved, nullptr);
}

/**
 * @brief 测试不同容器类型的内存计算
 */
TEST_F (CachePoolTest, MemoryCalculation)
{
    std::size_t const initialMemory = cachePool->MemoryUsage ();

    // 添加不同大小的容器
    auto* smallVec = new std::vector<int>{ 1, 2, 3 };
    auto* largeVec = new std::vector<int> ();
    largeVec->resize (1000, 42);

    ASSERT_TRUE (cachePool->Put ("small", smallVec));
    std::size_t const memoryAfterSmall = cachePool->MemoryUsage ();

    ASSERT_TRUE (cachePool->Put ("large", largeVec));
    std::size_t const memoryAfterLarge = cachePool->MemoryUsage ();

    // 验证内存使用量递增
    ASSERT_GT (memoryAfterSmall, initialMemory);
    ASSERT_GT (memoryAfterLarge, memoryAfterSmall);

    std::cout << "Memory progression:" << '\n';
    std::cout << "Initial: " << initialMemory << " bytes" << '\n';
    std::cout << "After small vector: " << memoryAfterSmall << " bytes" << '\n';
    std::cout << "After large vector: " << memoryAfterLarge << " bytes" << '\n';
}

/**
 * @brief 集成测试 - 模拟实际使用场景
 */
TEST_F (CachePoolTest, IntegrationTest)
{
    // 创建独立的缓存池进行集成测试，使用较短的清理间隔
    auto testCachePool = std::make_unique<SG::DBManager::CachePool> (10 * 1024, std::chrono::milliseconds (200));

    // 启动后台清理
    testCachePool->StartCleanupThread ();

    // 模拟数据库查询结果缓存 - 使用STL容器
    // 使用 vector 存储查询结果数据
    for (int query = 1; query <= 5; ++query)
    {
        auto* result = new std::vector<std::pair<int, std::string>> ();
        result->push_back ({ query * 10, "data_" + std::to_string (query) });
        result->push_back ({ query * 10 + 1, "metadata_" + std::to_string (query) });
        result->push_back ({ query * 10 + 2, "timestamp_2025-08-22" });

        std::string const cacheKey = "query_result_" + std::to_string (query);
        ASSERT_TRUE (testCachePool->Put (cacheKey, result, std::chrono::milliseconds (300)));  // 300ms TTL
    }

    // 验证所有查询结果都能获取
    for (int query = 1; query <= 5; ++query)
    {
        std::string const cacheKey = "query_result_" + std::to_string (query);
        auto*             result   = testCachePool->Get<std::vector<std::pair<int, std::string>>> (cacheKey);
        ASSERT_NE (result, nullptr);
        ASSERT_EQ (result->size (), 3);
        ASSERT_EQ ((*result)[0].first, query * 10);
        ASSERT_EQ ((*result)[0].second, "data_" + std::to_string (query));
    }

    // 等待部分数据过期 - 缩短等待时间
    std::this_thread::sleep_for (std::chrono::milliseconds (600));

    // 验证数据已过期
    for (int query = 1; query <= 5; ++query)
    {
        std::string const cacheKey = "query_result_" + std::to_string (query);
        auto*             result   = testCachePool->Get<std::vector<std::pair<int, std::string>>> (cacheKey);
        ASSERT_EQ (result, nullptr);
    }

    testCachePool->StopCleanupThread ();

    // 输出最终统计
    std::cout << "Final integration test statistics:" << '\n';
    std::cout << testCachePool->GetStatistics () << '\n';
}
